/*
 * Copyright (C) 2016-2018, LomboTech Co.Ltd.
 * Author: lomboswer <lomboswer@lombotech.com>
 *
 * Lombo n7 DMA controller register operations
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <linux/types.h>
#include <mach/csp/soc_define.h>
#include "dma_operate.h"

/* DMAC Version Register */
typedef union {
	u32 val;
	struct {
		u32 ver_l:5;
		u32 rsvd0:3;
		u32 ver_h:3;
		u32 rsvd1:1;
		u32 comp:1;
		u32 rsvd2:19;
	} bits;
} reg_dmac_ver_t;

/* DMAC Channel Enable Register0 */
typedef union {
	u32 val;
	struct {
		u32 ch0_en:1;
		u32 ch1_en:1;
		u32 ch2_en:1;
		u32 ch3_en:1;
		u32 ch4_en:1;
		u32 ch5_en:1;
		u32 ch6_en:1;
		u32 ch7_en:1;
		u32 ch0_en_we:1;
		u32 ch1_en_we:1;
		u32 ch2_en_we:1;
		u32 ch3_en_we:1;
		u32 ch4_en_we:1;
		u32 ch5_en_we:1;
		u32 ch6_en_we:1;
		u32 ch7_en_we:1;
		u32 rsvd0:16;
	} bits;
} reg_dmac_ch_en0_t;

/* DMAC Channel Enable Register1 */
typedef union {
	u32 val;
	struct {
		u32 ch0_abort:1;
		u32 ch1_abort:1;
		u32 ch2_abort:1;
		u32 ch3_abort:1;
		u32 ch4_abort:1;
		u32 ch5_abort:1;
		u32 ch6_abort:1;
		u32 ch7_abort:1;
		u32 ch0_abort_we:1;
		u32 ch1_abort_we:1;
		u32 ch2_abort_we:1;
		u32 ch3_abort_we:1;
		u32 ch4_abort_we:1;
		u32 ch5_abort_we:1;
		u32 ch6_abort_we:1;
		u32 ch7_abort_we:1;
		u32 rsvd0:16;
	} bits;
} reg_dmac_ch_en1_t;

/* DMAC Combined Interrupt Status Register */
typedef union {
	u32 val;
	struct {
		u32 ch0_int_pd:1;
		u32 ch1_int_pd:1;
		u32 ch2_int_pd:1;
		u32 ch3_int_pd:1;
		u32 ch4_int_pd:1;
		u32 ch5_int_pd:1;
		u32 ch6_int_pd:1;
		u32 ch7_int_pd:1;
		u32 rsvd0:8;
		u32 common_reg_int_pd:1;
		u32 rsvd1:15;
	} bits;
} reg_dmac_comb_int_pd_t;

/* DMAC Combined Interrupt Status Register */
typedef union {
	u32 val;
	struct {
		u32 dbg_en:1;
		u32 rsvd0:31;
	} bits;
} reg_dmac_dbg_en_t;

/* DMAC Channel[x] Source Address Register */
typedef union {
	u32 val;
	struct {
		u32 addr:32;
	} bits;
} reg_dmac_chx_src_addr_t;

/* DMAC Channel[x] Destination Address Register */
typedef union {
	u32 val;
	struct {
		u32 addr:32;
	} bits;
} reg_dmac_chx_dst_addr_t;

/* DMAC Channel[x] Block Length Register */
typedef union {
	u32 val;
	struct {
		u32 len:22;
		u32 rsvd0:10;
	} bits;
} reg_dmac_chx_blk_len_t;

/* DMAC Channel[x] Control Register0 */
typedef union {
	u32 val;
	struct {
		u32 rsvd0:4;
		u32 sag:1;
		u32 rsvd1:1;
		u32 dag:1;
		u32 rsvd2:1;
		u32 swidth:3;
		u32 dwidth:3;
		u32 src_blen:4;
		u32 dst_blen:4;
		u32 rsvd3:10;
	} bits;
} reg_dmac_chx_ctrl0_t;

/* DMAC Channel[x] Control Register1 */
typedef union {
	u32 val;
	struct {
		u32 rsvd0:26;
		u32 int_enable:1;
		u32 rsvd1:3;
		u32 lli_last:1;
		u32 lli_valid:1;
	} bits;
} reg_dmac_chx_ctrl1_t;

/* DMAC Channel[x] Configuration Register0 */
typedef union {
	u32 val;
	struct {
		u32 src_trans_type:2;
		u32 dst_trans_type:2;
		u32 rsvd0:28;
	} bits;
} reg_dmac_chx_cfg0_t;

/* DMAC Channel[x] Configuration Register1 */
typedef union {
	u32 val;
	struct {
		u32 trans_dir:3;
		u32 rsvd0:4;
		u32 srp:5;
		u32 drp:5;
		u32 prio:3;
		u32 rsvd1:3;
		u32 src_osr_lmt:4;
		u32 dst_osr_lmt:4;
		u32 rsvd2:1;
	} bits;
} reg_dmac_chx_cfg1_t;

/* DMAC Channel[x] Linked List Pointer Register */
typedef union {
	u32 val;
	struct {
		u32 llp0:32;
	} bits;
} reg_dmac_chx_llp_t;

/* DMAC Channel[x] Status Register0 */
typedef union {
	u32 val;
	struct {
		u32 com_blen:22;
		u32 rsvd0:10;
	} bits;
} reg_dmac_chx_stat0_t;

/* DMAC Channel[x] Status Register1 */
typedef union {
	u32 val;
	struct {
		u32 fifo_left:15;
		u32 rsvd0:17;
	} bits;
} reg_dmac_chx_stat1_t;

/* DMAC Channel[x] Resume Transfer Register */
typedef union {
	u32 val;
	struct {
		u32 resume:1;
		u32 rsvd0:31;
	} bits;
} reg_dmac_chx_resume_trans_t;

/* DMAC Channel[x] Interrupt Pending Register */
typedef union {
	u32 val;
	struct {
		u32 blk:1;
		u32 tran:1;
		u32 half_blk:1;
		u32 src_transcomp:1;
		u32 dst_transcomp:1;
		u32 src_dec_err:1;
		u32 dst_dec_err:1;
		u32 src_slv_err:1;
		u32 dst_slv_err:1;
		u32 lli_rd_dec_err:1;
		u32 lli_wr_dec_err:1;
		u32 lli_rd_slv_err:1;
		u32 lli_wr_slv_err:1;
		u32 lli_invalid_err:1;
		u32 rsvd0:17;
		u32 abort:1;
	} bits;
} reg_dmac_chx_int_pd_t;

/* DMAC Channel[x] Interrupt Enable Register */
typedef union {
	u32 val;
	struct {
		u32 blk:1;
		u32 tran:1;
		u32 half_blk:1;
		u32 src_transcomp:1;
		u32 dst_transcomp:1;
		u32 src_dec_err:1;
		u32 dst_dec_err:1;
		u32 src_slv_err:1;
		u32 dst_slv_err:1;
		u32 lli_rd_dec_err:1;
		u32 lli_wr_dec_err:1;
		u32 lli_rd_slv_err:1;
		u32 lli_wr_slv_err:1;
		u32 lli_invalid_err:1;
		u32 rsvd0:17;
		u32 abort:1;
	} bits;
} reg_dmac_chx_int_en_t;

/* DMAC Channel[x] Interrupt Clear Pending Register */
typedef union {
	u32 val;
	struct {
		u32 blk:1;
		u32 tran:1;
		u32 half_blk:1;
		u32 src_transcomp:1;
		u32 dst_transcomp:1;
		u32 src_dec_err:1;
		u32 dst_dec_err:1;
		u32 src_slv_err:1;
		u32 dst_slv_err:1;
		u32 lli_rd_dec_err:1;
		u32 lli_wr_dec_err:1;
		u32 lli_rd_slv_err:1;
		u32 lli_wr_slv_err:1;
		u32 lli_invalid_err:1;
		u32 rsvd0:17;
		u32 abort:1;
	} bits;
} reg_dmac_chx_int_clr_t;

/* DMAC Channel[x] Interrupt Clear Pending Register */
typedef union {
	u32 val;
	struct {
		u32 dbg_en:1;
		u32 rsvd0:31;
	} bits;
} reg_dmac_chx_dbg_en_t;

/* dma channel */
typedef struct tag_dma_chan {
	reg_dmac_chx_src_addr_t		chx_src_addr;		/* 0100 */
	u32				res0[1];
	reg_dmac_chx_dst_addr_t		chx_dst_addr;		/* 0108 */
	u32				res1[1];
	reg_dmac_chx_blk_len_t		chx_blk_len;		/* 0110 */
	u32				res2[1];
	reg_dmac_chx_ctrl0_t		chx_ctrl0;		/* 0118 */
	reg_dmac_chx_ctrl1_t		chx_ctrl1;		/* 011C */
	reg_dmac_chx_cfg0_t		chx_cfg0;		/* 0120 */
	reg_dmac_chx_cfg1_t		chx_cfg1;		/* 0124 */
	reg_dmac_chx_llp_t		chx_llp;		/* 0128 */
	u32				res3[1];
	reg_dmac_chx_stat0_t		chx_stat0;		/* 0130 */
	reg_dmac_chx_stat1_t		chx_stat1;		/* 0134 */
	u32				res4[4];
	reg_dmac_chx_resume_trans_t	chx_resume_trans;	/* 0148 */
	u32				res5[15];
	reg_dmac_chx_int_pd_t		chx_int_pd;		/* 0188 */
	u32				res6[1];
	reg_dmac_chx_int_en_t		chx_int_en;		/* 0190 */
	u32				res7[1];
	reg_dmac_chx_int_clr_t		chx_int_clr;		/* 0198 */
	u32				res8[21];
	reg_dmac_chx_dbg_en_t		chx_dbg_en;		/* 01F0 */
	u32				res9[3];
} dma_chan_t;

/* reg_dmac_t bank */
typedef struct tag_dmac {
	reg_dmac_ver_t			ver;		/* 0000 */
	u32				res0[5];
	reg_dmac_ch_en0_t		ch_en0;		/* 0018 */
	reg_dmac_ch_en1_t		ch_en1;		/* 001C */
	u32				res1[4];
	reg_dmac_comb_int_pd_t		comb_int_pd;	/* 0030 */
	u32				res2[39];
	reg_dmac_dbg_en_t		dbg_en;		/* 00D0 */
	u32				res3[11];
	dma_chan_t			dma_chan[8];	/* 0100 */
} reg_dmac_t;

/*
 * dma controller register offset define
 */
#define VER_OFFSET		0x0000
#define CH_EN0_OFFSET		0x0018
#define CH_EN1_OFFSET		0x001C
#define COMB_INT_PD_OFFSET	0x0030
#define DBG_EN_OFFSET		0x00D0
#define CH_SRC_ADDR_OFFSET	0x0100
#define CH_DEST_ADDR_OFFSET	0x0108
#define CH_BLK_LEN_OFFSET	0x0110
#define CH_CTRL0_OFFSET		0x0118
#define CH_CTRL1_OFFSET		0x011C
#define CH_CFG0_OFFSET		0x0120
#define CH_CFG1_OFFSET		0x0124
#define CH_LLP_OFFSET		0x0128
#define CH_STAT0_OFFSET		0x0130
#define CH_STAT1_OFFSET		0x0134
#define CH_RESUME_TRANS_OFFSET	0x0148
#define CH_INT_PD_OFFSET	0x0188
#define CH_INT_EN_OFFSET	0x0190
#define CH_INT_CLR_OFFSET	0x0198
#define CH_DBG_EN_OFFSET	0x01F0

/* offset between channel */
#define DMA_CHANNEL_OFFSET	0x0100

/**
 * channel device source and destination request define
 */
#define MEM_RT_RP		0
#define SPI0_RX_SRP		1
#define SPI0_TX_DSP		2
#define SPI1_RX_SRP		3
#define SPI1_TX_DSP		4
#define SPI2_RX_SRP		5
#define SPI2_TX_DSP		6
#define I2C0_RX_SRP		7
#define I2C0_TX_DRP		8
#define I2C1_RX_SRP		9
#define I2C1_TX_DRP		10
#define I2C2_RX_SRP		11
#define I2C2_TX_DRP		12
#define I2C3_RX_SRP		13
#define I2C3_TX_DRP		14
#define UART0_RX_SRP		15
#define UART0_TX_DRP		16
#define UART1_RX_SRP		17
#define UART1_TX_DRP		18
#define UART2_RX_SRP		19
#define UART2_TX_DRP		20
#define UART3_RX_SRP		21
#define UART3_TX_DRP		22
#define I2S_RX_SRP		23
#define I2S_TX_DRP		24
#define TON_TX_DRP		26

/**
 * csp_dma_set_channel_enable - enable or disable special channel
 */
void csp_dma_set_channel_enable(u32 index, u32 value, void *base)
{
	void *reg = base + CH_EN0_OFFSET;
	reg_dmac_ch_en0_t ch_en0_reg;

	ch_en0_reg.val = readl(reg);
	switch (index) {
	case 0:
		ch_en0_reg.bits.ch0_en = value;
		ch_en0_reg.bits.ch0_en_we = value;
		break;
	case 1:
		ch_en0_reg.bits.ch1_en = value;
		ch_en0_reg.bits.ch1_en_we = value;
		break;
	case 2:
		ch_en0_reg.bits.ch2_en = value;
		ch_en0_reg.bits.ch2_en_we = value;
		break;
	case 3:
		ch_en0_reg.bits.ch3_en = value;
		ch_en0_reg.bits.ch3_en_we = value;
		break;
	case 4:
		ch_en0_reg.bits.ch4_en = value;
		ch_en0_reg.bits.ch4_en_we = value;
		break;
	case 5:
		ch_en0_reg.bits.ch5_en = value;
		ch_en0_reg.bits.ch5_en_we = value;
		break;
	case 6:
		ch_en0_reg.bits.ch6_en = value;
		ch_en0_reg.bits.ch6_en_we = value;
		break;
	case 7:
		ch_en0_reg.bits.ch7_en = value;
		ch_en0_reg.bits.ch7_en_we = value;
		break;
	default:
		return;
	}

	writel(ch_en0_reg.val, reg);

	return;
}

/**
 * csp_dma_set_channel_abort - enable or disable special channel
 */
void csp_dma_set_channel_abort(u32 index, u32 value, void *base)
{
	void *reg = base + CH_EN1_OFFSET;
	reg_dmac_ch_en1_t ch_en1_reg;

	ch_en1_reg.val = readl(reg);
	switch (index) {
	case 0:
		ch_en1_reg.bits.ch0_abort = value;
		ch_en1_reg.bits.ch0_abort_we = value;
		break;
	case 1:
		ch_en1_reg.bits.ch1_abort = value;
		ch_en1_reg.bits.ch1_abort_we = value;
		break;
	case 2:
		ch_en1_reg.bits.ch2_abort = value;
		ch_en1_reg.bits.ch2_abort_we = value;
		break;
	case 3:
		ch_en1_reg.bits.ch3_abort = value;
		ch_en1_reg.bits.ch3_abort_we = value;
		break;
	case 4:
		ch_en1_reg.bits.ch4_abort = value;
		ch_en1_reg.bits.ch4_abort_we = value;
		break;
	case 5:
		ch_en1_reg.bits.ch5_abort = value;
		ch_en1_reg.bits.ch5_abort_we = value;
		break;
	case 6:
		ch_en1_reg.bits.ch6_abort = value;
		ch_en1_reg.bits.ch6_abort_we = value;
		break;
	case 7:
		ch_en1_reg.bits.ch7_abort = value;
		ch_en1_reg.bits.ch7_abort_we = value;
		break;
	default:
		return;
	}

	writel(ch_en1_reg.val, reg);

	return;
}

/**
 * csp_dma_resume_channel_trans - resume block chain lli transfer
 */
void csp_dma_resume_channel_trans(u32 index, void *base)
{
	void *reg = base + index * DMA_CHANNEL_OFFSET + CH_RESUME_TRANS_OFFSET;
	reg_dmac_chx_resume_trans_t resume_trans_reg;

	resume_trans_reg.val = readl(reg);
	resume_trans_reg.bits.resume = CH_RESUME_TRANS;
	writel(resume_trans_reg.val, reg);
}

/**
 * csp_dma_set_channel_cfg - set channel config
 */
void csp_dma_set_channel_cfg(u32 index, u32 direction, u32 priority,
				    u32 slave_id, void *base)
{
	void *cfg0_reg = base + index * DMA_CHANNEL_OFFSET + CH_CFG0_OFFSET;
	void *cfg1_reg = base + index * DMA_CHANNEL_OFFSET + CH_CFG1_OFFSET;
	reg_dmac_chx_cfg0_t ch_cfg0_reg;
	reg_dmac_chx_cfg1_t ch_cfg1_reg;

	ch_cfg0_reg.val = readl(cfg0_reg);
	ch_cfg1_reg.val = readl(cfg1_reg);

	ch_cfg0_reg.bits.src_trans_type = CH_CHAINS_TRANS;
	ch_cfg0_reg.bits.dst_trans_type = CH_CHAINS_TRANS;

	ch_cfg1_reg.bits.trans_dir = direction;
	ch_cfg1_reg.bits.prio = priority;

	if (direction == CH_MEM_TO_MEM) {
		ch_cfg1_reg.bits.srp = MEM_RT_RP;
		ch_cfg1_reg.bits.drp = MEM_RT_RP;
	} else if (direction == CH_MEM_TO_DEV) {
		ch_cfg1_reg.bits.srp = MEM_RT_RP;
		ch_cfg1_reg.bits.drp = slave_id;
	} else if (direction == CH_DEV_TO_MEM) {
		ch_cfg1_reg.bits.drp = MEM_RT_RP;
		ch_cfg1_reg.bits.srp = slave_id;
	}

	writel(ch_cfg0_reg.val, cfg0_reg);
	writel(ch_cfg1_reg.val, cfg1_reg);
}

/**
 * csp_dma_org_channel_ctrl0 - orginate channel control0 register value
 */
u32 csp_dma_org_channel_ctrl0(u32 sag, u32 dag, u32 swidth, u32 dwidth,
				      u32 src_blen, u32 dst_blen)
{
	reg_dmac_chx_ctrl0_t ch_ctrl0_reg;

	ch_ctrl0_reg.val = 0;
	ch_ctrl0_reg.bits.sag = sag;
	ch_ctrl0_reg.bits.dag = dag;
	ch_ctrl0_reg.bits.swidth = swidth;
	ch_ctrl0_reg.bits.dwidth = dwidth;
	ch_ctrl0_reg.bits.src_blen = src_blen;
	ch_ctrl0_reg.bits.dst_blen = dst_blen;

	return ch_ctrl0_reg.val;
}

/**
 * csp_dma_org_channel_ctrl1 - orginate channel control1 register value
 */
u32 csp_dma_org_channel_ctrl1(void)
{
	reg_dmac_chx_ctrl1_t ch_ctrl1_reg;

	ch_ctrl1_reg.val = 0;
	ch_ctrl1_reg.bits.int_enable = CH_LLI_INT_ENABLE;
	ch_ctrl1_reg.bits.lli_last = CH_LLI_NO_LAST;
	ch_ctrl1_reg.bits.lli_valid = CH_LLI_VALID;

	return ch_ctrl1_reg.val;
}

/**
 * csp_dma_set_channel_lli_last - set lli last to true
 */
void csp_dma_set_channel_lli_last(u32 *value, bool is_last)
{
	reg_dmac_chx_ctrl1_t *ch_ctrl1_reg = (reg_dmac_chx_ctrl1_t *)value;
	if (is_last)
		ch_ctrl1_reg->bits.lli_last = CH_LLI_LAST;
	else
		ch_ctrl1_reg->bits.lli_last = CH_LLI_NO_LAST;
}

/**
 * csp_dma_set_channel_llp - set first chain llp address
 */
void csp_dma_set_channel_llp(u32 index, u32 addr, void *base)
{
	void *reg = base + index * DMA_CHANNEL_OFFSET + CH_LLP_OFFSET;

	reg_dmac_chx_llp_t ch_llp_reg;
	ch_llp_reg.val = addr;
	writel(ch_llp_reg.val, reg);
}

/**
 * csp_dma_set_channel_int_en - set channel interrupt enable
 */
void csp_dma_set_channel_int_en(u32 index, u32 half_blk, u32 tran,
					u32 blk, void *base)
{
	void *reg = base + index * DMA_CHANNEL_OFFSET + CH_INT_EN_OFFSET;
	reg_dmac_chx_int_en_t ch_int_en_reg;

	ch_int_en_reg.val = 0;
	ch_int_en_reg.bits.blk = blk;
	ch_int_en_reg.bits.tran = tran;
	ch_int_en_reg.bits.half_blk = half_blk;
	ch_int_en_reg.bits.src_transcomp = CH_INT_DISABLE;
	ch_int_en_reg.bits.dst_transcomp = CH_INT_DISABLE;
	ch_int_en_reg.bits.src_dec_err = CH_INT_ENABLE;
	ch_int_en_reg.bits.dst_dec_err = CH_INT_ENABLE;
	ch_int_en_reg.bits.src_slv_err = CH_INT_ENABLE;
	ch_int_en_reg.bits.dst_slv_err = CH_INT_ENABLE;
	ch_int_en_reg.bits.lli_rd_dec_err = CH_INT_ENABLE;
	ch_int_en_reg.bits.lli_wr_dec_err = CH_INT_ENABLE;
	ch_int_en_reg.bits.lli_rd_slv_err = CH_INT_ENABLE;
	ch_int_en_reg.bits.lli_wr_slv_err = CH_INT_ENABLE;
	ch_int_en_reg.bits.lli_invalid_err = CH_INT_ENABLE;
	ch_int_en_reg.bits.abort = CH_INT_DISABLE;

	writel(ch_int_en_reg.val, reg);
}

/**
 * csp_dma_clear_channel_all_int - clear channel all interrupt
 */
void csp_dma_clear_channel_all_int(u32 index, void *base)
{
	void *reg = base + index * DMA_CHANNEL_OFFSET + CH_INT_CLR_OFFSET;

	writel(CH_ALL_BITS, reg);
}

/**
 * csp_dma_check_ch_comb_int_pd - check channel combine interrupt pending
 */
u32 csp_dma_is_ch_comb_int_pd(u32 index, void *base)
{
	void *reg = base + COMB_INT_PD_OFFSET;
	reg_dmac_comb_int_pd_t comb_int_pd_reg;
	u32 value = 0;

	comb_int_pd_reg.val = readl(reg);
	switch (index) {
	case 0:
		value = comb_int_pd_reg.bits.ch0_int_pd;
		break;
	case 1:
		value = comb_int_pd_reg.bits.ch1_int_pd;
		break;
	case 2:
		value = comb_int_pd_reg.bits.ch2_int_pd;
		break;
	case 3:
		value = comb_int_pd_reg.bits.ch3_int_pd;
		break;
	case 4:
		value = comb_int_pd_reg.bits.ch4_int_pd;
		break;
	case 5:
		value = comb_int_pd_reg.bits.ch5_int_pd;
		break;
	case 6:
		value = comb_int_pd_reg.bits.ch6_int_pd;
		break;
	case 7:
		value = comb_int_pd_reg.bits.ch7_int_pd;
		break;
	default:
		break;
	}

	return value;
}

/**
 * csp_dma_is_ch_tran_int_pd - check channel trans interrupt pending
 */
u32 csp_dma_is_ch_tran_int_pd(u32 index, void *base)
{
	void *reg_pd = base + index * DMA_CHANNEL_OFFSET + CH_INT_PD_OFFSET;
	void *reg_en = base + index * DMA_CHANNEL_OFFSET + CH_INT_EN_OFFSET;
	reg_dmac_chx_int_pd_t ch_int_pd_reg;
	reg_dmac_chx_int_en_t ch_int_en_reg;
	u32 value;

	ch_int_en_reg.val = readl(reg_en);
	ch_int_pd_reg.val = readl(reg_pd);
	value = ch_int_pd_reg.bits.tran & ch_int_en_reg.bits.tran;
	return value;
}

/**
 * csp_dma_is_ch_blk_int_pd - check channel blk interrupt pending
 */
u32 csp_dma_is_ch_blk_int_pd(u32 index, void *base)
{
	void *reg_pd = base + index * DMA_CHANNEL_OFFSET + CH_INT_PD_OFFSET;
	void *reg_en = base + index * DMA_CHANNEL_OFFSET + CH_INT_EN_OFFSET;
	reg_dmac_chx_int_pd_t ch_int_pd_reg;
	reg_dmac_chx_int_en_t ch_int_en_reg;
	u32 value;

	ch_int_en_reg.val = readl(reg_en);
	ch_int_pd_reg.val = readl(reg_pd);
	value = ch_int_pd_reg.bits.blk & ch_int_en_reg.bits.blk;
	return value;
}

/**
 * csp_dma_is_ch_hblk_int_pd - check channel blk interrupt pending
 */
u32 csp_dma_is_ch_hblk_int_pd(u32 index, void *base)
{
	void *reg_pd = base + index * DMA_CHANNEL_OFFSET + CH_INT_PD_OFFSET;
	void *reg_en = base + index * DMA_CHANNEL_OFFSET + CH_INT_EN_OFFSET;
	reg_dmac_chx_int_pd_t ch_int_pd_reg;
	reg_dmac_chx_int_en_t ch_int_en_reg;
	u32 value;

	ch_int_en_reg.val = readl(reg_en);
	ch_int_pd_reg.val = readl(reg_pd);
	value = ch_int_pd_reg.bits.half_blk & ch_int_en_reg.bits.half_blk;
	return value;
}

/**
 * csp_dma_is_ch_blk_int_pd - check channel err interrupt pending
 */
u32 csp_dma_is_ch_err_int_pd(u32 index, void *base)
{
	void *reg = base + index * DMA_CHANNEL_OFFSET + CH_INT_PD_OFFSET;
	reg_dmac_chx_int_pd_t ch_int_pd_reg;
	reg_dmac_chx_int_pd_t reg_val;

	reg_val.val = 0;
	ch_int_pd_reg.val = readl(reg);
	reg_val.bits.src_dec_err = ch_int_pd_reg.bits.src_dec_err;
	reg_val.bits.dst_dec_err = ch_int_pd_reg.bits.dst_dec_err;
	reg_val.bits.src_slv_err = ch_int_pd_reg.bits.src_slv_err;
	reg_val.bits.dst_slv_err = ch_int_pd_reg.bits.dst_slv_err;
	reg_val.bits.lli_rd_dec_err = ch_int_pd_reg.bits.lli_rd_dec_err;
	reg_val.bits.lli_wr_dec_err = ch_int_pd_reg.bits.lli_wr_dec_err;
	reg_val.bits.lli_rd_slv_err = ch_int_pd_reg.bits.lli_rd_slv_err;
	reg_val.bits.lli_wr_slv_err = ch_int_pd_reg.bits.lli_wr_slv_err;
	reg_val.bits.lli_invalid_err = ch_int_pd_reg.bits.lli_invalid_err;

	return reg_val.val;
}

/**
 * csp_dma_is_ch_abort_int_pd - check channel abort interrupt pending
 */
u32 csp_dma_is_ch_abort_int_pd(u32 index, void *base)
{
	void *reg = base + index * DMA_CHANNEL_OFFSET + CH_INT_PD_OFFSET;
	reg_dmac_chx_int_pd_t ch_int_pd_reg;
	u32 value;

	ch_int_pd_reg.val = readl(reg);
	value = ch_int_pd_reg.bits.abort;
	return value;
}

/**
 * csp_dma_halt_channel_trans - halt block chain lli transfer
 */
void csp_dma_halt_channel_trans(u32 index, void *base)
{
	return;
};

/**
 * csp_dma_is_ch_halt_int_pd - check channel halt interrupt pending
 */
u32 csp_dma_is_ch_halt_int_pd(u32 index, void *base)
{
	return 0;
}

/**
 * csp_dma_clear_ch_halt_int_pd - clear channel halt interrupt pending
 */
void csp_dma_clear_ch_halt_int_pd(u32 index, void *base)
{
	return;
}

/**
 * csp_dma_clear_ch_tran_int_pd - clear channel trans interrupt pending
 */
void csp_dma_clear_ch_tran_int_pd(u32 index, void *base)
{
	void *reg = base + index * DMA_CHANNEL_OFFSET + CH_INT_CLR_OFFSET;
	reg_dmac_chx_int_clr_t ch_int_clr_reg;

	ch_int_clr_reg.val = readl(reg);
	ch_int_clr_reg.bits.tran = CH_CLEAR_PENDING;
	writel(ch_int_clr_reg.val, reg);
}

/**
 * csp_dma_clear_ch_blk_int_pd - clear channel blk interrupt pending
 */
void csp_dma_clear_ch_blk_int_pd(u32 index, void *base)
{
	void *reg = base + index * DMA_CHANNEL_OFFSET + CH_INT_CLR_OFFSET;
	reg_dmac_chx_int_clr_t ch_int_clr_reg;

	ch_int_clr_reg.val = readl(reg);
	ch_int_clr_reg.bits.blk = CH_CLEAR_PENDING;
	writel(ch_int_clr_reg.val, reg);
}

/**
 * csp_dma_clear_ch_hblk_int_pd - clear channel half blk interrupt pending
 */
void csp_dma_clear_ch_hblk_int_pd(u32 index, void *base)
{
	void *reg = base + index * DMA_CHANNEL_OFFSET + CH_INT_CLR_OFFSET;
	reg_dmac_chx_int_clr_t ch_int_clr_reg;

	ch_int_clr_reg.val = readl(reg);
	ch_int_clr_reg.bits.half_blk = CH_CLEAR_PENDING;
	writel(ch_int_clr_reg.val, reg);
}

/**
 * csp_dma_clear_ch_err_int_pd - clear channel err interrupt pending
 */
void csp_dma_clear_ch_err_int_pd(u32 index, void *base)
{
	void *reg = base + index * DMA_CHANNEL_OFFSET + CH_INT_CLR_OFFSET;
	reg_dmac_chx_int_clr_t ch_int_clr_reg;

	ch_int_clr_reg.val = readl(reg);
	ch_int_clr_reg.bits.src_dec_err = CH_CLEAR_PENDING;
	ch_int_clr_reg.bits.dst_dec_err = CH_CLEAR_PENDING;
	ch_int_clr_reg.bits.src_slv_err = CH_CLEAR_PENDING;
	ch_int_clr_reg.bits.dst_slv_err = CH_CLEAR_PENDING;
	ch_int_clr_reg.bits.lli_rd_dec_err = CH_CLEAR_PENDING;
	ch_int_clr_reg.bits.lli_wr_dec_err = CH_CLEAR_PENDING;
	ch_int_clr_reg.bits.lli_rd_slv_err = CH_CLEAR_PENDING;
	ch_int_clr_reg.bits.lli_wr_slv_err = CH_CLEAR_PENDING;
	ch_int_clr_reg.bits.lli_invalid_err = CH_CLEAR_PENDING;

	writel(ch_int_clr_reg.val, reg);
}

/**
 * csp_dma_clear_ch_abort_int_pd - clear channel abort interrupt pending
 */
void csp_dma_clear_ch_abort_int_pd(u32 index, void *base)
{
	void *reg = base + index * DMA_CHANNEL_OFFSET + CH_INT_CLR_OFFSET;
	reg_dmac_chx_int_clr_t ch_int_clr_reg;

	ch_int_clr_reg.val = readl(reg);
	ch_int_clr_reg.bits.abort = CH_CLEAR_PENDING;

	writel(ch_int_clr_reg.val, reg);
}
